package com.gwd.task.untils;


import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhiyongming
 * @date 2020/11/10 16:23
 * 封装List Predicate, 把其中的功能做成了WebFlux风格
 */
public class ListPredicate<T> {
    private final CriteriaBuilder cb;
    private final CriteriaQuery<?> query;
    private final Root<T> root;
    private final List<Predicate> predicates;

    public static ListPredicate<?> of(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        return new ListPredicate<>(root, query, cb);
    }

    private ListPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        this.root = root;
        this.query = query;
        this.cb = cb;
        predicates = new ArrayList<>();
    }

    public ListPredicate<?> equal(String target, Object source) {
        if (source==null || source.toString().equals("")) {
            return this;
        }
        predicates.add(cb.equal(root.get(target), source));
        return this;
    }

    public ListPredicate<?> notEqual(String target, Object source) {
        if (source==null || source.toString().equals("")) {
            return this;
        }
        predicates.add(cb.notEqual(root.get(target), source));
        return this;
    }

    public ListPredicate<?> likeLeft(String target, Object source) {
        if (source==null || source.toString().equals("")) {
            return this;
        }
        predicates.add(cb.like(root.get(target), "%"+source));
        return this;
    }

    public ListPredicate<?> likeRight(String target, Object source) {
        if (source==null || source.toString().equals("")) {
            return this;
        }
        predicates.add(cb.like(root.get(target), source+"%"));
        return this;
    }

    public ListPredicate<?> like(String target, Object source) {
        if (source==null || source.toString().equals("")) {
            return this;
        }
        predicates.add(cb.like(root.get(target),"%"+source+"%"));
        return this;
    }

    public ListPredicate<?> inNumber(String target, String source, String split) {
        if (sourceFilter(source)) {
            return this;
        }
        /*
         * 1.获取分隔符
         * 2.字符串去空格，分割成数组
         * 3.字符串数组转整形数组
         */
        split = split==null?",":split;
        String[] ss = source.replaceAll(" ", "").split(split);
        List<Integer> list = Arrays.stream(ss).map(Integer::valueOf).collect(Collectors.toList());

        predicates.add(root.get(target).in(list));
        return this;
    }

    public ListPredicate<?> inString(String target, String source, String split) {
        if (sourceFilter(source)) {
            return this;
        }
        split = split==null?",":split;
        String[] ss = source.replaceAll(" ", "").split(split);
        List<String> list = Arrays.stream(ss).map(String::valueOf).collect(Collectors.toList());

        predicates.add(root.get(target).in(list));
        return this;
    }

    public ListPredicate<?> between(String target, String[] ob) {
        if (ob == null) {
            return this;
        }

        predicates.add(cb.between(root.get(target), ob[0], ob[1]));
        return this;
    }

    public ListPredicate<?> between(String target, String begin, String end) {
        if (sourceFilter(begin) && sourceFilter(end)) {
            return this;
        }

        predicates.add(cb.between(root.get(target), begin, end));
        return this;
    }

    public ListPredicate<?> ge(String target, String value) {
        if (value == null || value.equals("")) {
            return this;
        }

        predicates.add(cb.greaterThanOrEqualTo(root.get(target), value));
        return this;
    }

    public ListPredicate<?> gt(String target, String value) {
        if (value == null || value.equals("")) {
            return this;
        }

        predicates.add(cb.lessThanOrEqualTo(root.get(target), value));
        return this;
    }

    public ListPredicate<?> finish() {
        query.where(predicates.toArray(new Predicate[0]));
        return this;
    }

    public Predicate getRestriction() {
        return query.getRestriction();
    }

    private boolean sourceFilter(String source) {
        return source == null || source.equals("");
    }
}
